{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.0.0\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "print(tf.__version__)\n",
    "# from Ipython import display\n",
    "from matplotlib import pyplot as plt\n",
    "import random\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2.1 gen_dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<tf.Tensor: id=31, shape=(2,), dtype=float32, numpy=array([0.24220389, 0.41220406], dtype=float32)>,\n",
       " <tf.Tensor: id=35, shape=(), dtype=float32, numpy=3.3064191>)"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "num_inputs = 2\n",
    "num_examples = 1000\n",
    "true_w = [2, -3.4]\n",
    "true_b = 4.2\n",
    "features = tf.random.normal((num_examples, num_inputs),stddev = 1)\n",
    "labels = true_w[0] * features[:,0] + true_w[1] * features[:,1] + true_b\n",
    "labels += tf.random.normal(labels.shape,stddev=0.01)\n",
    "\n",
    "features[0], labels[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x108c818ad0>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 252x180 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "def set_figsize(figsize=(3.5, 2.5)):\n",
    "    plt.rcParams['figure.figsize'] = figsize\n",
    "\n",
    "set_figsize()\n",
    "plt.scatter(features[:, 1], labels, 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2.2 read data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "def data_iter(batch_size, features, labels):\n",
    "    num_examples = len(features)\n",
    "    indices = list(range(num_examples))\n",
    "    random.shuffle(indices)\n",
    "    for i in range(0, num_examples, batch_size):\n",
    "        j = indices[i: min(i+batch_size, num_examples)]\n",
    "        yield tf.gather(features, axis=0, indices=j), tf.gather(labels, axis=0, indices=j)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[-1.8040096  -0.15478396]\n",
      " [ 0.30197513  0.7226112 ]\n",
      " [ 1.3643339   1.2256716 ]\n",
      " [ 0.64083093  0.00985407]\n",
      " [-0.9130684   1.2870392 ]\n",
      " [-0.73635167  0.8616958 ]\n",
      " [-1.3767787  -0.7688884 ]\n",
      " [ 0.26842278 -0.40469164]\n",
      " [ 1.1865063   0.6506257 ]\n",
      " [ 0.24220389  0.41220406]] [ 1.1166337   2.3442128   2.7511618   5.4408355  -2.003743   -0.19769916\n",
      "  4.0604286   6.11232     4.3865256   3.3064191 ]\n"
     ]
    }
   ],
   "source": [
    "batch_size = 10\n",
    "\n",
    "for X, y in data_iter(batch_size, features, labels):\n",
    "    print(X, y)\n",
    "    break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2.3 initialize weight"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "w = tf.Variable(tf.random.normal((num_inputs, 1), stddev=0.01))\n",
    "b = tf.Variable(tf.zeros((1,)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2.4 define model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def linreg(X, w, b):\n",
    "    return tf.matmul(X, w) + b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2.5 define loss"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def squared_loss(y_hat, y):\n",
    "    return (y_hat - tf.reshape(y, y_hat.shape)) ** 2 /2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2.6 define optimization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def sgd(params, lr, batch_size, grads):\n",
    "    \"\"\"Mini-batch stochastic gradient descent.\"\"\"\n",
    "    for i, param in enumerate(params):\n",
    "        param.assign_sub(lr * grads[i] / batch_size)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2.7 training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 1, loss 0.028907\n",
      "epoch 2, loss 0.000101\n",
      "epoch 3, loss 0.000049\n"
     ]
    }
   ],
   "source": [
    "lr = 0.03\n",
    "num_epochs = 3\n",
    "net = linreg\n",
    "loss = squared_loss\n",
    "\n",
    "for epoch in range(num_epochs):\n",
    "    for X, y in data_iter(batch_size, features, labels):\n",
    "        with tf.GradientTape() as t:\n",
    "            t.watch([w,b])\n",
    "            l = loss(net(X, w, b), y)\n",
    "        grads = t.gradient(l, [w, b])\n",
    "        sgd([w, b], lr, batch_size, grads)\n",
    "    train_l = loss(net(features, w, b), labels)\n",
    "    print('epoch %d, loss %f' % (epoch + 1, tf.reduce_mean(train_l)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "([2, -3.4], <tf.Variable 'Variable:0' shape=(2, 1) dtype=float32, numpy=\n",
       " array([[ 1.9994558],\n",
       "        [-3.3993363]], dtype=float32)>)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "true_w, w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(4.2,\n",
       " <tf.Variable 'Variable:0' shape=(1,) dtype=float32, numpy=array([4.199041], dtype=float32)>)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "true_b, b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
